
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
#endregion

namespace XNALibrary
{
    /// <summary>
    /// This is a class to handle keyboard, controller, mouse input
    /// i.e it encapsulates keyboard, controller, mouse inputs in a single class
    /// </summary>
    public partial class InputHandler
    {
        #region Fields and properties

        Game game;

        KeyboardHandler keyboard = new KeyboardHandler();

        ButtonHandler gamePadHandler = new ButtonHandler();
        GamePadState[] gamePads = new GamePadState[4];

#if !XBOX360
        MouseState mouseState;
        MouseState prevMouseState;
#endif

        bool allowsExiting = false;

        public KeyboardHandler KeyboardHandler
        {
            get { return (keyboard); }
        }

        public ButtonHandler ButtonHandler
        {
            get { return (gamePadHandler); }
        }

        public GamePadState[] GamePads
        {
            get { return (gamePads); }
        }

#if !XBOX360
        public MouseState MouseState
        {
            get { return (mouseState); }
        }

        public MouseState PreviousMouseState
        {
            get { return (prevMouseState); }
        }
#endif

        #endregion Fields and properties

        public InputHandler(Game game) 
        { 
            this.game = game;
            allowsExiting = false;
            Initialize();
        }
        public InputHandler(Game game, bool allowsExiting)
        {
            this.allowsExiting = allowsExiting;
            this.game = game;
            Initialize();
        }

        private void Initialize ()
        {
#if !XBOX360
            game.IsMouseVisible = true;
            prevMouseState = Mouse.GetState();
#endif
        }

        public void Update()
        {
            Update(null);
        }

        /// <summary>
        /// Update input states and should be called from Game.Update
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public void Update(GameTime gameTime)
        {
            keyboard.Update();
            gamePadHandler.Update();
            if (allowsExiting)
            {
                if (keyboard.IsKeyDown(Keys.Escape))
                    game.Exit();
                if (gamePadHandler.WasButtonPressed(0, Buttons.Back))
                    game.Exit();
            }
            
#if !XBOX360
            prevMouseState = mouseState;
            mouseState = Mouse.GetState();
#endif

            gamePads[0] = GamePad.GetState(PlayerIndex.One);
            gamePads[1] = GamePad.GetState(PlayerIndex.Two);
            gamePads[2] = GamePad.GetState(PlayerIndex.Three);
            gamePads[3] = GamePad.GetState(PlayerIndex.Four);
        }

        public bool WasPressed(int playerIndex, Buttons button, Keys keys)
        {
            if (keyboard.WasKeyPressed(keys) || 
                gamePadHandler.WasButtonPressed(playerIndex, button))
                return (true);
            else
                return (false);
        }

    }

    public class ButtonHandler
    {
        private GamePadState[] prevGamePadsState = new GamePadState[4];
        private GamePadState[] gamePadsState = new GamePadState[4];

        public ButtonHandler()
        {
            prevGamePadsState[0] = GamePad.GetState(PlayerIndex.One);
            prevGamePadsState[1] = GamePad.GetState(PlayerIndex.Two);
            prevGamePadsState[2] = GamePad.GetState(PlayerIndex.Three);
            prevGamePadsState[3] = GamePad.GetState(PlayerIndex.Four);
        }

        public void Update()
        {
            // Set our previous state to our new state
            prevGamePadsState[0] = gamePadsState[0];
            prevGamePadsState[1] = gamePadsState[1];
            prevGamePadsState[2] = gamePadsState[2];
            prevGamePadsState[3] = gamePadsState[3];

            // Get our new state
            gamePadsState[0] = GamePad.GetState(PlayerIndex.One);
            gamePadsState[1] = GamePad.GetState(PlayerIndex.Two);
            gamePadsState[2] = GamePad.GetState(PlayerIndex.Three);
            gamePadsState[3] = GamePad.GetState(PlayerIndex.Four);
        }

        public bool WasButtonPressed(Buttons button)
        {
            return WasButtonPressed(0, button);
        }

        public bool WasButtonPressed(int playerIndex, Buttons button)
        {
            int pi = playerIndex;
            switch(button)
            {
                case Buttons.A:
                    {
                        return (gamePadsState[pi].Buttons.A == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.A == ButtonState.Released);
                    }
                case Buttons.B:
                    {
                        return (gamePadsState[pi].Buttons.B == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.B == ButtonState.Released);
                    }
                case Buttons.Back:
                    {
                        return (gamePadsState[pi].Buttons.Back == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.Back == ButtonState.Released);
                    }
                case Buttons.LeftShoulder:
                    {
                        return (gamePadsState[pi].Buttons.LeftShoulder == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.LeftShoulder == ButtonState.Released);
                    }
                case Buttons.LeftStick:
                    {
                        return (gamePadsState[pi].Buttons.LeftStick == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.LeftStick == ButtonState.Released);
                    }
                case Buttons.RightShoulder:
                    {
                        return (gamePadsState[pi].Buttons.RightShoulder == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.RightShoulder == ButtonState.Released);
                    }
                case Buttons.RightStick:
                    {
                        return (gamePadsState[pi].Buttons.RightStick == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.RightStick == ButtonState.Released);
                    }
                case Buttons.Start:
                    {
                        return (gamePadsState[pi].Buttons.Start == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.Start == ButtonState.Released);
                    }
                case Buttons.X:
                    {
                        return (gamePadsState[pi].Buttons.X == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.X == ButtonState.Released);
                    }
                case Buttons.Y:
                    {
                        return (gamePadsState[pi].Buttons.Y == ButtonState.Pressed &&
                            prevGamePadsState[pi].Buttons.Y == ButtonState.Released);
                    }

                case Buttons.DPadDown:
                    {
                        return (gamePadsState[pi].DPad.Down == ButtonState.Pressed &&
                            prevGamePadsState[pi].DPad.Down == ButtonState.Released);
                    }
                case Buttons.DPadUp:
                    {
                        return (gamePadsState[pi].DPad.Up == ButtonState.Pressed &&
                            prevGamePadsState[pi].DPad.Up == ButtonState.Released);
                    }
                case Buttons.DPadLeft:
                    {
                        return (gamePadsState[pi].DPad.Left == ButtonState.Pressed &&
                            prevGamePadsState[pi].DPad.Left == ButtonState.Released);
                    }
                case Buttons.DPadRight:
                    {
                        return (gamePadsState[pi].DPad.Right == ButtonState.Pressed &&
                            prevGamePadsState[pi].DPad.Right == ButtonState.Released);
                    }
                default:
                    return false;
            }
        }
    }

    public class KeyboardHandler
    {
        private KeyboardState prevKeyboardState;
        private KeyboardState keyboardState;

        public KeyboardHandler()
        {
            prevKeyboardState = Keyboard.GetState();
        }

        public bool IsKeyDown(Keys key)
        {
            return (keyboardState.IsKeyDown(key));
        }

        public bool IsHoldingKey(Keys key)
        {
            return(keyboardState.IsKeyDown(key) && prevKeyboardState.IsKeyDown(key));
        }

        public bool WasKeyPressed(Keys key)
        {
            return (keyboardState.IsKeyDown(key) && prevKeyboardState.IsKeyUp(key));
        }

        public bool HasReleasedKey(Keys key)
        {
            return (keyboardState.IsKeyUp(key) && prevKeyboardState.IsKeyDown(key));
        }

        public void Update()
        {
            // Set our previous state to our new state
            prevKeyboardState = keyboardState;

            // Get our new state
            keyboardState = Keyboard.GetState();
        }
    }
}


